package com.xiaoq.oauth2.controller;


import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.utils.OAuthUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.xiaoq.coms.RestException;
import com.xiaoq.coms.util.ClientIPHandler;
import com.xiaoq.oauth2.OAuth2Constants;
import com.xiaoq.oauth2.OAuth2SvrErrorCode;
import com.xiaoq.oauth2.service.OAuth2Service;
import com.xiaoq.oauth2.thirdpartclient.entity.Client;
import com.xiaoq.oauth2.thirdpartclient.service.ClientService;

/*
    授权码模式（authorization code）
 */
@Controller
class ACModeAuthorizeController {

    private static Logger logger = LoggerFactory.getLogger(ACModeAuthorizeController.class);

    @Autowired
    private ClientService clientService;

    @Autowired
    private OAuth2Service oAuth2Service;


    //第三方应用（ClientApp）请求授权码时,首先需要自身信息的注册,并获得ClientKey与ClientSecret,
    //然后用clientKey与ClientSecret去请求
    //授权码,具体如下:
    //1,验证ClientKey;
    //2,验证ClientSecret;
    //3,转向登录页面,资源持有人登录,并进行授权
    //4,ClientApp得到授权码
    @RequestMapping(value = "/authorize", method = RequestMethod.GET)
    public Object showAuthorizeForm(Model model, HttpServletRequest request)
            throws URISyntaxException, OAuthSystemException {
        try {
            //构建OAuth 授权请求
            OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);

            Client client = clientService.findByClientKey(oauthRequest.getClientId());
            logger.info(" client = "+client);
            //检查传入的客户端ClientId(实际上就是ClientKey)是否正确
            if (client == null) {
                OAuthResponse response =
                        OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                                .setError(OAuthError.TokenResponse.INVALID_CLIENT)
                                .setErrorDescription(OAuth2Constants.INVALID_CLIENT_ID)
                                .buildJSONMessage();
                return new ResponseEntity<>(response.getBody(), HttpStatus.valueOf(
                        response.getResponseStatus()));
            }
            logger.info("clientId = " + client.getClientKey());
            logger.info("clientSecret = " + client.getClientSecret());

            //验证客户端安全AppSecret是否正确
            if (oauthRequest.getClientSecret() == null || !oauthRequest.getClientSecret().equals(
                    client.getClientSecret())) {
                OAuthResponse response = OAuthASResponse
                        .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
                        .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
                        .setErrorDescription(OAuth2Constants.INVALID_CLIENT_SECRET)
                        .buildJSONMessage();

                return new ResponseEntity<>(response.getBody(), HttpStatus.valueOf(
                        response.getResponseStatus()));
            }
            model.addAttribute("client", client);
            return "oauth2/oauth2login";
        } catch (OAuthProblemException e) {
            //出错处理
            String redirectUri = e.getRedirectUri();
            if (OAuthUtils.isEmpty(redirectUri)) {
                //告诉客户端没有传入redirectUri直接报错
                throw new RestException(HttpStatus.valueOf(OAuth2SvrErrorCode.NEED_REDIRECT_URI.httpStatus), OAuth2SvrErrorCode.NEED_REDIRECT_URI.errorMsg, OAuth2SvrErrorCode.NEED_REDIRECT_URI.errorCode);
            }
            throw new RestException(e.getMessage());

        }
    }

    @RequestMapping(value = "/authorize", method = RequestMethod.POST)
    public Object authorize(Model model, HttpServletRequest request)
            throws URISyntaxException, OAuthSystemException {
        String loginName = request.getParameter("loginName");
        String password = request.getParameter("password");
        String responseType = request.getParameter("response_type");

        logger.info("loginName = " + loginName);
        logger.info("password = " + password);
        logger.info("responseType = " + responseType);

        String ip = ClientIPHandler.getClientIP(request);
        logger.debug("the client ip address is : "+ip);

        String authorizationCode = oAuth2Service.loginAndGenerateAuthCode(loginName, password, ip,responseType);

        //进行OAuth响应构建
        OAuthASResponse.OAuthAuthorizationResponseBuilder builder =
                OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
        //设置授权码
        builder.setCode(authorizationCode);
        //得到到客户端重定向地址
        String redirectURI = request.getParameter(OAuth.OAUTH_REDIRECT_URI)+"?username="+loginName;

        logger.info("redirectURI = " + redirectURI);

        //构建响应
        final OAuthResponse response = builder.location(redirectURI).buildQueryMessage();

        //根据OAuthResponse返回ResponseEntity响应
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(new URI(response.getLocationUri()));
        return new ResponseEntity(headers, HttpStatus.valueOf(response.getResponseStatus()));
    }

    @RequestMapping(value = "/access_token", method = RequestMethod.GET)
    public String showAccessTokenForm() {
        return "/oauth2/requestTokenWithAuthCode";
    }
}